//websocket工具库
function json_parse(str) {
	var p = new Promise(function(resolve, reject) {
		var cc = JSON.parse(str);
		resolve(cc);
	});
	return p;
}
class Websocket { 
	constructor({
		heartCheck = true,
		isReconnection = true
	}) {
		this._options = null;
		// 是否连接
		this._isOpen = false;
		// 当前网络状态
		this._netWork = true;
		// 是否人为退出
		this._isClosed = false;
		// 心跳检测频率
		this._timeout = 2.5 * 60 * 1000;
		this._timeoutObj = null;
		// 当前重连次数
		this._connectNum = 0;
		// 心跳检测和断线重连开关，true为启用，false为关闭
		this._heartCheck = heartCheck;
		this._isReconnection = isReconnection;
		this._socketMsgQueue = []; //待发送消息队列
		this._eventHandler = {
			onOpen: [],
			onError: [],
			onClose: [],
			online:[]
		};
		this._messageHandler = {}; //消息处理
		this._onSocketOpened();
		this._onReceivedMsg();
		this._onSocketClosed();
		this._onSocketError();
		this._onNetworkChange();		
	}
	addMsgHandler(cmd, handler) {
		//console.error(cmd)
		this._messageHandler[cmd] = handler;
	}
	addEventHandler(event, handler) {
		/* var ev = this._eventHandler[event]
		if (!ev) {
			this._eventHandler[event] = []
		} */
		this._eventHandler[event].push(handler);
	}
	// 心跳检查重置
	_resetPing() {
		clearTimeout(this._timeoutObj);
		return this;
	}
	// 心跳检测开始
	_startPing() {
		let _this = this;
		this._timeoutObj = setInterval(() => {
			_this.sendMsg(Cmd.ping())
		}, this._timeout);
	}
	/**
	 * 建立websocket连接
	 * @param {Object} options {url:"",success:function(){},fail:function(){}}
	 */
	connect(options) {
		let _this = this;

		typeof options == "string" && (options = {
			url: options
		})
		this._options = options;		
		if (this._isOpen) {
			console.log("您已经登录了");
		} else {			
			// 检查网络
			uni.getNetworkType({
				success(result) {

					if (result.networkType != 'none') {
						// 开始建立连接
						uni.connectSocket({
							url: options.url,
							success(res) {
								//console.error("444666666444444")
								//console.log('参数的类型必须为函数')
								if (typeof options.success == "function") {
									options.success(res)
								}
								/* else {
									console.log('参数的类型必须为函数')
								} */
							},
							fail(err) {
								if (typeof options.fail == "function") {
									options.fail(err)
								} else {
									console.log('参数的类型必须为函数')
								}
							}
						})
					} else {
						console.log('网络已断开');
						_this._netWork = false;
						// 网络断开后显示model
						uni.showModal({
							title: '网络错误',
							content: '请重新打开网络',
							showCancel: false,
							success: function(res) {
								if (res.confirm) {
									console.log('用户点击确定')
								}
							}
						})
					}
				}
			})
		}
		return this
	}
	_onSocketOpened() {
		let _this = this;
		uni.onSocketOpen(res => {
			console.log('websocket已打开');
			// 打开已登录开关
			this._isOpen = true;
			// 发送心跳,防止服务器端主动断开
			if (this._heartCheck) {
				this._resetPing()._startPing();
			}
			// 发送登录信息
			/* uni.sendSocketMessage({
				// 这里是第一次建立连接所发送的信息，应由前后端商量后决定
				data: JSON.stringify({
					"key": 'value'
				})
			}) */
			for (let i = 0; i < _this._socketMsgQueue.length; i++) {
				this.sendMsg({
					data: _this._socketMsgQueue[i]
				})
			}
			_this.socketMsgQueue = []
			//打开事件
			if (_this._eventHandler['onOpen'].length > 0) {
				//_this._eventHandler['onOpen'](res);
				_this._eventHandler['onOpen'].forEach(function(e, i) {
					e(res)
				});
			}
			// 打开网络开关
			this._netWork = true;
		})
	}
	/**
	 * 发送websocket消息
	 * @param {Object} options 为string类型或者 {data:objcet,success:function(){},fail:function(){}}
	 */
	sendMsg(options) {
		typeof options == "string" && (options = {
			data: options
		})
		if (this._isOpen) {
			uni.sendSocketMessage({
				data: options.data,
				success(res) {
					if (typeof options.success == "function") {
						options.success(res)
					}
					/* else {
						console.log('参数的类型必须为函数')
					} */
				},
				fail(err) {
					if (typeof options.fail == "function") {
						options.fail(err)
					}
					/* else {
						console.log('参数的类型必须为函数')
					} */
				}
			})
		} else {
			this.socketMsgQueue.push(options.data)
		}

	}
	/**
	 * 接收服务器返回的消息
	 * @param {Object} callBack
	 */
	_onReceivedMsg() {
		var that = this
		uni.onSocketMessage(res => {
			//console.error("wwwww"+res.data)
			json_parse(res.data).then(function(message) {
				console.log(message) 
				message = JSON.parse(message)
				var cmd = message['cmd'];
				//console.error(that._messageHandler) 
				if (that._messageHandler[cmd]) {
					that._messageHandler[cmd](message);
				} else {
					console.log(`cmd ${cmd} hava not handler`, message);
				}

			}).catch(function(e) {
				console.log("cmd parse faild", e);
				console.log(e);
			})
			/* if (typeof callBack == "function") {
				callBack(msg)
			} else {
				console.log('参数的类型必须为函数')
			} */
		})
	}
	// 重连方法，会根据时间频率越来越慢
	_reConnect() {
		var options = this._options;
		let timer, _this = this;
		if (this._connectNum < 20) {
			timer = setTimeout(() => {
				_this.connect(options)
			}, 3000)
			this._connectNum += 1;
		} else if (this._connectNum < 50) {
			timer = setTimeout(() => {
				_this.connect(options)
			}, 10000)
			this._connectNum += 1;
		} else {
			timer = setTimeout(() => {
				_this.connect(options)
			}, 450000) 
			this._connectNum += 1;
		}
	}
	// 监听websocket连接关闭
	_onSocketClosed() {
		var that = this;
		uni.onSocketClose(err => {
			console.log('当前websocket连接已关闭,错误信息为:' + JSON.stringify(err));
			// 停止心跳连接
			if (this._heartCheck) {
				this._resetPing();
			}
			// 关闭已登录开关
			this._isOpen = false;
			//事件监听
			/* if (this._eventHandler['onClose']) {
				this._eventHandler['onClose'](res);
			} */
			if (that._eventHandler['onClose'].length > 0) {
				that._eventHandler['onClose'].forEach(function(e, i) {
					e(res)
				});
			}
			// 检测是否是用户自己退出小程序
			if (!this._isClosed) {
				// 进行重连
				if (this._isReconnection) {
					this._reConnect()
				}
			}
		})
	}
	_onSocketError() {
		var that = this
		uni.onSocketError(function(res) {
			this._resetPing()
			console.log('onSocketError', res);
			/* if (this._eventHandler['onError']) {
				this._eventHandler['onError'](res);
			} */
			if (that._eventHandler['onError'].length > 0) {
				that._eventHandler['onError'].forEach(function(e, i) {
					e(res)
				});
			}
		})
	}

	// 检测网络变化
	_onNetworkChange() {
		uni.onNetworkStatusChange(res => {
			console.log('当前网络状态:' + res.isConnected);
			if (!this._netWork) {
				this._isOpen = false;
				// 进行重连
				if (this._isReconnection) {
					this._reConnect()
				}
			}
		})
	}
	// 关闭websocket连接
	close() { 
		uni.closeSocket();
		this._isClosed = true;
	}
}
export {
	Websocket
};

export var Cmd = {
	getCmdMsg(cmd, data, channel, sender) {
		return JSON.stringify({
			cmd: cmd, //命令，字符串
			data: data, //数据
			sender: sender, //发送者信息{clientid,username,pic}
			channel: channel
		});
	},
	/**
	 * 主要用于心跳检测。客户端不应理睬
	 */
	ping() {
		return this.getCmdMsg('ping');
	},
	/**
	 * 打招呼
	 */
	hello(channel, sender) {
		return this.getCmdMsg('hello', null, channel, sender);
	},
	/**
	 * 离开频道
	 * @param {Object} channel
	 * @param {Object} sender
	 */
	bye(channel, sender) {
		return this.getCmdMsg('bye', null, channel, sender);
	},
	msg(data, channel, sender) {
		//发送消息
		return this.getCmdMsg('msg', data, channel, sender);
	},
	/**
	 * 上线
	 */
	online() {
		return this.getCmdMsg('online');
	},
	/**
	 * 下线
	 */
	offline() {
		return this.getCmdMsg('offline');
	}
};
